package com.jms.boot.context;

import com.jms.boot.listener.chanin.ApplicationCloseChain;
import com.jms.boot.listener.chanin.ApplicationStartChain;
import com.jms.framework.context.ApplicationContext;
import com.jms.framework.listener.context.ListenerContext;
import com.jms.framework.event.ApplicationCloseEvent;
import com.jms.framework.event.ApplicationEvent;
import com.jms.framework.event.ApplicationStartEvent;
import com.jms.framework.exception.PropertyAlreadySetException;
import com.jms.framework.listener.ApplicationListener;
import com.jms.framework.listener.ListenerChain;
import com.jms.framework.listener.Order;
import com.jms.tools.util.ReflectUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;

/**
 * JmsBoot监听器上下文实现类，负责初始化和销毁应用程序事件监听器链
 */
public class JmsBootListenerContext implements ListenerContext {

    // 单例模式，保证全局只有一个监听器上下文实例
    private volatile static JmsBootListenerContext listenerContext;

    // 日志记录器，用于记录初始化和销毁过程中的信息
    private static final Logger logger = LogManager.getLogger(JmsBootListenerContext.class);

    // 启动监听器链，用于在应用启动时按顺序执行监听器
    private ListenerChain startListenerChain;

    // 关闭监听器链，用于在应用关闭时按顺序执行监听器
    private ListenerChain closeListenerChain;

    // 应用上下文，存储所有bean实例
    private ApplicationContext applicationContext;

    // 私有构造方法，防止外部实例化
    private JmsBootListenerContext() {
    }

    /**
     * 设置应用上下文实例
     *
     * @param applicationContext 应用上下文实例
     * @throws PropertyAlreadySetException 如果已经设置了应用上下文，则抛出此异常
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        if (this.applicationContext != null) {
            throw new PropertyAlreadySetException(ApplicationContext.class, "applicationContext");
        }
        this.applicationContext = applicationContext;
    }

    /**
     * 获取监听器上下文的单例实例
     *
     * @return 监听器上下文实例
     */
    public static JmsBootListenerContext getInstance() {
        if (listenerContext == null) {
            synchronized (JmsBootListenerContext.class) {
                if (listenerContext == null) {
                    listenerContext = new JmsBootListenerContext();
                }
            }
        }
        return listenerContext;
    }

    /**
     * 初始化监听器上下文，包括构建启动和关闭监听器链
     */
    @Override
    @SuppressWarnings("unchecked")
    public void init() {
        logger.info("The listener context starts initializing.");
        try {
            // 分别存储启动和关闭事件监听器
            ArrayList<ApplicationListener<ApplicationStartEvent>> startListeners = new ArrayList<>();
            ArrayList<ApplicationListener<ApplicationCloseEvent>> closeListeners = new ArrayList<>();

            // 获取所有bean实例，从中筛选出ApplicationListener的实现类
            Object[] beans = applicationContext.getBeans();
            for (Object bean : beans) {
                Class<?> cl = bean.getClass();
                if (ApplicationListener.class.isAssignableFrom(cl)) {
                    // 获取泛型类型，判断是启动还是关闭事件监听器
                    for (Type type : ReflectUtils.getAllGenericInterfaces(cl)) {
                        if (type instanceof ParameterizedType) {
                            ParameterizedType parameterizedType = (ParameterizedType) type;
                            Type rawType = parameterizedType.getRawType();
                            if (rawType.equals(ApplicationListener.class)) {
                                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                                if (actualTypeArguments.length > 0) {
                                    Type genericType = actualTypeArguments[0];
                                    if (genericType.equals(ApplicationStartEvent.class)) {
                                        startListeners.add((ApplicationListener<ApplicationStartEvent>) bean);
                                        logger.debug("Loaded listener: " + cl.getName());
                                    } else if (genericType.equals(ApplicationCloseEvent.class)) {
                                        closeListeners.add((ApplicationListener<ApplicationCloseEvent>) bean);
                                        logger.debug("Loaded listener: " + cl.getName());
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 对监听器进行排序，根据Order接口的实现
            sort(startListeners);
            sort(closeListeners);

            // 构建关闭和启动事件监听器链
            closeListenerChain = ApplicationCloseChain.getInstance(closeListeners, new ApplicationCloseEvent(applicationContext));
            startListenerChain = ApplicationStartChain.getInstance(startListeners, new ApplicationStartEvent(applicationContext));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        logger.info("The listener context initialization is complete.");
    }

    /**
     * 对监听器列表进行排序
     *
     * @param listeners 监听器列表
     * @param <T>       事件类型
     */
    public static <T extends ApplicationEvent> void sort(ArrayList<ApplicationListener<T>> listeners) {
        listeners.sort((o1, o2) -> {
            int value1 = 0;
            int value2 = 0;
            if (o1 instanceof Order) {
                value1 = ((Order) o1).getOrderValue();
            }
            if (o2 instanceof Order) {
                value2 = ((Order) o2).getOrderValue();
            }
            return value1 - value2;
        });
    }

    /**
     * 销毁监听器上下文，包括清理启动和关闭监听器链
     */
    @Override
    public void destroy() {
        logger.info("The listener context starts destroying.");
        startListenerChain = null;
        closeListenerChain = null;
        logger.info("The listener context destruction is complete.");
    }

    /**
     * 获取启动监听器链
     *
     * @return 启动监听器链
     */
    @Override
    public ListenerChain getStartListenerChain() {
        return startListenerChain;
    }

    /**
     * 获取关闭监听器链
     *
     * @return 关闭监听器链
     */
    @Override
    public ListenerChain getCloseListenerChain() {
        return closeListenerChain;
    }
}
